// **
// **  Базовый класс для создателя объекта
// **

class CreatorBase: public QObject
{
Q_OBJECT
    void	*_obj;										// созданный объект
protected:		virtual void *Allocation (void) = 0;	// тут будет создаваться объект
public slots:	void allocate (void)		{ emit setObject (Allocation ()); }	// слот создания объекта
signals:		void setObject (void *Obj);				// выдача созданного объекта
};

// **
// **  Базовый класс для создания потока
// **

class ThreadedObjectBase: public QObject
{
    Q_OBJECT

protected:
    QThread	*_thread;				// поток

    virtual void SetObjectPointer (void *Ptr) = 0;		// тут будет присваиваться объект
    ThreadedObjectBase (QObject *parent = 0): QObject (parent), _thread (0) {}		// инициализация предка

    void starting (CreatorBase *Creator, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true)		// запуск нового потока
    {
        bool res;							// признак успешности установки сигналов-слотов
        _thread = new QThread;		// создание потока
        Creator->moveToThread (_thread);		// перенос _creator в поток
        res = connect (_thread, SIGNAL (started ()), Creator, SLOT (allocate ()));				Q_ASSERT_X (res, "connect", "connection is not established");	// запуск потока _thread вызывает создание объекта Creator-ом
        res = connect (Creator, SIGNAL (setObject (void*)), this, SLOT (setObject (void*)));	Q_ASSERT_X (res, "connect", "connection is not established");	// Creat-ор выдает адрес объекта
        if (ToDeleteLaterThread)			// отложенное удаление thread?
        {	res = connect (_thread, SIGNAL (finished ()), _thread, SLOT (deleteLater ()));		Q_ASSERT_X (res, "connect", "connection is not established");	}	// завершение потока _thread вызывает отложенное удаление объекта
        _thread->start (Priority);			// установка приоритета
    }

public:
    // . управление
    virtual ~ThreadedObjectBase (void)		{ if (_thread) delete _thread; }			// создание иерархии деструкторов
    QThread *thread (void)	{ return _thread; }				// поток, владеющий объектом

    // . состояние
    const QThread *cthread (void) const	{ return _thread; }		// поток, владеющий объектом

signals:
    void objectIsReady (void);				// сигнал "объект готов"

private slots:
    void setObject (void *Obj)				{ SetObjectPointer (Obj); emit objectIsReady (); }		// получение адреса объекта
};	// class ThreadedObjectBase

// **
// **  Создание потока
// **

template <class T>
class ThreadedObject: public ThreadedObjectBase
{
private:
    template <class T> class Creator: public CreatorBase		// создатель объекта в потоке
    { protected: void *Allocation (void) { return reinterpret_cast <void*> (new T); } };
    Creator<T> *_creator;		// класс создания объекта в потоке

protected:
    T*	_obj;						// объект
    const char	*_finished_signal;			// сигнал "окончание работы объекта"
    const char	*_terminate_slot;			// слот "остановка работы"
    bool		_to_delete_later_object;	// установить "отложенне удаление объекта?

    void SetObjectPointer (void *Ptr)		// установка связей объекта
    {
        bool res;							// признак успешности установки сигналов-слотов

        _obj = reinterpret_cast <T*> (Ptr);	// установка указателя на объект

        if (_finished_signal)				// установить сигнал "окончание работы объекта"?
        {	res = connect (_obj, _finished_signal, _thread, SLOT (quit ()));			Q_ASSERT_X (res, "connect", "connection is not established");	}	// по окончанию работы объекта поток будет завершен
        if (_terminate_slot)				// установить слот "остановка работы"?
        {	res = connect (_thread, SIGNAL (finished ()), _obj, _terminate_slot);	Q_ASSERT_X (res, "connect", "connection is not established");	}	// перед остановкой потока будет вызван слот объекта "остановка работы"
        if (_to_delete_later_object && _finished_signal)	// установить отложенное удаление объекта?
        {	res = connect (_obj, _finished_signal, _obj, SLOT (deleteLater ()));	Q_ASSERT_X (res, "connect", "connection is not established");	}	// по окончанию работы объекта будет установлено отложенное удаление
    }

public:
    // . управление
    ThreadedObject (QObject *parent = 0): ThreadedObjectBase (parent), _obj (0), _creator (0) {}	// конструктор
    ~ThreadedObject  (void)	{ if (_creator) delete _creator; }		// деструктор
    void start (const char *FinishedSignal = 0, const char *TerminateSlot = 0, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true, bool ToDeleteLaterObject = true)		// запуск нового потока
    {
        _finished_signal = FinishedSignal;		// запоминание имени сигнала "окончание работы объекта"
        _terminate_slot = TerminateSlot;		// запоминание имени слота "остановка работы"
        _to_delete_later_object = ToDeleteLaterObject;	// запоминание установки отложенного удаление объекта
        starting (new Creator<T>, Priority, ToDeleteLaterThread);	// создание объекта
    }

    // . состояние
    bool objectIsCreated (void) const	{ return _obj != 0; }							// объект готов к работе?

    T* ptr (void) 				{ return reinterpret_cast <T*> (_obj); }			// указатель на объект
    const T* cptr (void) const	{ return reinterpret_cast <const T*> (_obj); }		// указатель на константный объект

    // . перегрузки
    operator T* (void)					{ return ptr (); }		// указатель на объект
    T* operator -> (void)				{ return ptr (); }		// указатель на объект
    operator const T* (void) const		{ return cptr (); }		// указатель на константный объект
    const T* operator -> (void) const	{ return cptr (); }		// указатель на константный объект
};	// class ThreadedObject

